package animix.blue.server.user.aop;

import animix.blue.server.common.bean.model.LogOperation;
import animix.blue.server.common.bean.model.User;
import animix.blue.server.common.bean.pojo.LogOperationAnno;
import animix.blue.server.common.bean.pojo.Result;
import animix.blue.server.common.bean.tool.UserInfo;
import animix.blue.server.common.utils.HttpUtils;
import animix.blue.server.user.service.UserService;
import eu.bitwalker.useragentutils.UserAgent;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class LogOperationAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private UserService userService;

    /**
     * 可以通过切点表达式指定需要拦截的package
     * 切点表达式：execution(...)
     * 这里使用注解形式
     */
    @Pointcut("@annotation(animix.blue.server.common.bean.pojo.LogOperationAnno)")
    public void logPointCut() {
    }

    /**
     * 环绕通知：在目标方法调用之前和之后调用，目标方法需要手动调用
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 手动执行方法
        Object proceed = point.proceed();
        try {
            // 获得方法名称
            String methodName = point.getSignature().getName();
            // 获得所有方法
            Method[] methods = point.getTarget().getClass().getMethods();
            for (Method method : methods) {
                LogOperationAnno logOperationAnno = method.getAnnotation(LogOperationAnno.class);
                if (logOperationAnno != null && method.getName().equals(methodName)) {
                    if (proceed instanceof Result) {
                        Result result = (Result) proceed;
                        if (result.getCode() == 200) {
                            // System.out.println(logOperationAnno.action());
                            // System.out.println(logOperationAnno.object());
                            // 获得User对象
                            // 从Header中取token
                            String token = request.getHeader("token");
                            if (StringUtils.isBlank(token)) {
                                // 参数中再取一次
                                token = request.getParameter("token");
                            }
                            UserInfo userInfo = (UserInfo) userService.getInfoByToken(token).getData();
                            User user = userInfo.getUser();
                            // 向MQ发送消息，记录操作日志
                            // 组装LogLogin对象
                            final LogOperation logOperation = new LogOperation();
                            logOperation.setUserId(user.getId());
                            logOperation.setUsername(user.getUsername());
                            logOperation.setOperated(new Date());
                            logOperation.setAction(logOperationAnno.action());
                            logOperation.setObject(logOperationAnno.object());
                            logOperation.setOperation(Arrays.toString(point.getArgs()));
                            logOperation.setIp(HttpUtils.getIpAddr(request));
                            //logOperation.setLocation(HttpUtils.getAddresses(logOperation.getIp()));
                            UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
                            logOperation.setTerminal(userAgent.getBrowser() + " " + userAgent.getBrowserVersion());
                            logOperation.setPlatform(userAgent.getOperatingSystem().getName());
                            // 发送消息
                            rabbitTemplate.convertAndSend("exchange.direct", "KEY_LOG_OPERATION", logOperation);
                        }
                    } else {
                        System.out.println("LogAspect: 不支持的返回值！");
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return proceed;
    }
}
